package DAO

import (
	"gopkg.in/ini.v1"
	"log"
	"os"
	"sync"

	"github.com/go-xorm/xorm"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"xorm.io/core"
	"xorm.io/xorm/caches"
)

var Engine *xorm.Engine
var logFile *os.File // 共享日志文件

type XormZapLogger struct {
	sugar   *zap.SugaredLogger
	showSQL bool
	logCh   chan []interface{}
	wg      sync.WaitGroup
}

func (l *XormZapLogger) Debug(v ...interface{}) {
	l.logCh <- v
}

func (l *XormZapLogger) Debugf(format string, v ...interface{}) {
	l.logCh <- []interface{}{format, v}
}

func (l *XormZapLogger) Error(v ...interface{}) {
	l.logCh <- v
}

func (l *XormZapLogger) Errorf(format string, v ...interface{}) {
	l.logCh <- []interface{}{format, v}
}

func (l *XormZapLogger) Info(v ...interface{}) {
	l.logCh <- v
}

func (l *XormZapLogger) Infof(format string, v ...interface{}) {
	l.logCh <- []interface{}{format, v}
}

func (l *XormZapLogger) Warn(v ...interface{}) {
	l.logCh <- v
}

func (l *XormZapLogger) Warnf(format string, v ...interface{}) {
	l.logCh <- []interface{}{format, v}
}

func (l *XormZapLogger) Level() core.LogLevel {
	return core.LOG_INFO
}

func (l *XormZapLogger) SetLevel(level core.LogLevel) {
	// 这里可以根据需要处理日志级别设置
}

func (l *XormZapLogger) ShowSQL(show ...bool) {
	if len(show) > 0 {
		l.showSQL = show[0]
	}
}

func (l *XormZapLogger) IsShowSQL() bool {
	return l.showSQL
}

func (l *XormZapLogger) Fatal(v ...interface{}) {
	l.logCh <- v
	// 可以根据需要进行其他处理，如退出程序
}

func (l *XormZapLogger) Fatalf(format string, v ...interface{}) {
	l.logCh <- []interface{}{format, v}
	// 可以根据需要进行其他处理，如退出程序
}

func (l *XormZapLogger) Panic(v ...interface{}) {
	l.logCh <- v
	// 可以根据需要进行其他处理，如触发 panic
}

func (l *XormZapLogger) Panicf(format string, v ...interface{}) {
	l.logCh <- []interface{}{format, v}
	// 可以根据需要进行其他处理，如触发 panic
}

func (l *XormZapLogger) startAsyncLogging() {
	go func() {
		for msg := range l.logCh {
			if len(msg) == 1 {
				l.sugar.Debug(msg[0])
			} else if len(msg) == 2 {
				format := msg[0].(string)
				args := msg[1].([]interface{})
				l.sugar.Debugf(format, args...)
			}
		}
		l.wg.Done()
	}()
}

func init() {
	var err error
	// 打开共享日志文件
	logFile, err = os.OpenFile("db.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatalf("Failed to open log file: %v", err)
	}

	// 从配置文件中读取数据库配置
	cfg, err := ini.Load("./Config/config.ini")
	if err != nil {
		log.Fatalf("Failed to load config: %v", err)
	}

	// 构建数据库连接字符串
	//dsn := cfg.Section("mysql").Key("username").String() + ":" + cfg.Section("mysql").Key("password").String() + "@" + cfg.Section("mysql").Key("host").String() + "/" + cfg.Section("mysql").Key("database").String() + "?charset=utf8mb4&parseTime=true"
	dsn := cfg.Section("mysql").Key("username").String() + ":" +
		cfg.Section("mysql").Key("password").String() + "@" +
		cfg.Section("mysql").Key("host").String() + "/" +
		cfg.Section("mysql").Key("database").String() +
		"?charset=utf8mb4&parseTime=true&loc=Asia%2FShanghai&parseTime=true"
	// 输入数据库连接信息
	log.Println("xorm 连接数据:", dsn)
	Engine, err = xorm.NewEngine("mysql", dsn)

	if err != nil {
		log.Fatalf("Failed to connect to database: %v", err)
	}
	Engine.SetMaxIdleConns(10)
	Engine.SetMaxOpenConns(1000)
	cacher := caches.NewLRUCacher(caches.NewMemoryStore(), 1000)
	Engine.SetDefaultCacher(cacher)

	encoderConfig := zapcore.EncoderConfig{
		TimeKey:        "time",
		LevelKey:       "level",
		NameKey:        "logger",
		CallerKey:      "caller",
		MessageKey:     "msg",
		StacktraceKey:  "stacktrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.ShortCallerEncoder,
	}

	newCore := zapcore.NewCore(
		zapcore.NewJSONEncoder(encoderConfig),
		zapcore.AddSync(logFile),
		zapcore.DebugLevel,
	)

	logger := zap.New(newCore)
	defer logger.Sync()
	sugar := logger.Sugar()

	xormLogger := &XormZapLogger{sugar: sugar, logCh: make(chan []interface{}, 100)}
	Engine.SetLogger(xormLogger)
	Engine.ShowSQL(true)

	// 启动异步日志处理
	xormLogger.startAsyncLogging()
}
